#include "embed.h"

void disable_irq(int irq)
{
	unsigned short pic;
	if (irq < 8) 
		pic = PIC1_MASK;
	else 
		pic = PIC2_MASK;
	
	unsigned char mascara = inportb(pic) | IRQ_MASK_BIT(irq); 
	outportb(pic, mascara);
}


void enable_irq(int irq)
{
	unsigned short pic;
	
	if (irq <= 7) 
		pic = PIC1_MASK;
	else 
		pic = PIC2_MASK;
		
	unsigned char mascara = inportb(pic) & (~IRQ_MASK_BIT(irq));
	outportb(pic, mascara); 
}


static Byte state_pic1;
static Byte state_pic2;

void enable_int()
{
	outportb(PIC1_MASK, state_pic1);
	outportb(PIC2_MASK, state_pic2);
}

void disable_int()
{
	state_pic1 = inportb(PIC1_MASK);
	state_pic2 = inportb(PIC2_MASK);
	
	outportb(PIC1_MASK, 0xFF); // Inibe as interrupções
	outportb(PIC2_MASK, 0xFF);
}

/** Draws a pixel of color "color" at screen coordinates x, y at memory address "base"
 */
void set_pixel(int x, int y, int color, char *base)
{
	if(x < 0 || x >= HRES || y < 0 || y >= VRES)
		return;
		
	*(base + y*HRES + x) = color;
}


int get_pixel(int x, int y, char *base)
{
	if(x < 0 || x >= HRES || y < 0 || y >= VRES)
		return -1;
		
	return (int)(*(base + y*HRES + x));
}


void clear_screen(char color, char *base)
{
	int x, y;
	for(y = 0; y < VRES; y++)
		for(x = 0; x < HRES; x++)
			set_pixel(x, y, color, base);
}


void draw_line(int xi, int yi, int xf, int yf, int color, char *base)
{
	//obter o comprimento da linha em x
	int x_size = xf - xi;
	if(x_size < 0)
		x_size = -x_size;
	
	//obter o comprimento da linha em y
	int y_size = yf - yi;
	if(y_size < 0)
		y_size = -y_size;
	
	int i;
	if(x_size > y_size) //dimensao maior e a horizontal
	{
		if(xf - xi < 0) //orientar a recta no sentido positivo de x
		{
			int aux = xi;
			xi = xf;
			xf = aux;
			aux = yi;
			yi = yf;
			yf = aux;
		}
		
		for(i = 0; i <= x_size; i++)
		{
			//regra de 3 simples; se x_size esta para y_size, entao i esta para y_point
			double y_point = (double)y_size * (double)i / (double)x_size;
			
			//desenhar pixel
			if(yf - yi < 0)
				set_pixel(xi + i, yi - (int)(y_point + 0.5), color, base);
			else
				set_pixel(xi + i, yi + (int)(y_point + 0.5), color, base);
		}
	}
		
	else //dimensao maior e a vertical
	{
		if(yf - yi < 0) //orientar a recta no sentido positivo de y
		{
			int aux = xi;
			xi = xf;
			xf = aux;
			aux = yi;
			yi = yf;
			yf = aux;
		}
		
		for(i = 0; i <= y_size; i++)
		{
			//regra de 3 simples; se y_size esta para x_size, entao i esta para x_point
			double x_point = (double)x_size * (double)i / (double)y_size;
			
			//desenhar pixel
			if(xf - xi < 0)
				set_pixel(xi - (int)(x_point + 0.5), yi + i, color, base);
			else
				set_pixel(xi + (int)(x_point + 0.5), yi + i, color, base);
		}
	}		
}


void drawCharAt(char c, int x, int y, int fore_color, int back_color,
				int char_scale, char* video_base, char* table)
{
	// posicao do caracter c em table (lida de po.dat)
	char* char_def = table + c * CHR_H;

	int i, j;
	Byte mask = 0x80;
	int color;
	int x_act, y_act, sx, sy;
	// usar operadores bitwise para isolar e testar cada um dos bits
	for (j = 0, y_act = y; j < CHR_H; j++, y_act += char_scale) // for each character row
	{
		for (i = 0, x_act = x; i < 8; i++, x_act += char_scale)		// for each pixel in row
		{
			color = (*char_def & (mask >> i)) ? fore_color : back_color;
			for(sx = 0; sx < char_scale; sx++)
					for(sy = 0; sy < char_scale; sy++)
						set_pixel(x_act + sx, y_act + sy, color, video_base);
		}
		char_def++;
	}
}	


void drawStringAt(char* str, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	while(str[i] != 0)
	{
		drawCharAt(str[i], x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		i++;
	}
}
		
		
void drawIntAt(int num, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	
	//se o numero for negativo, imprimir '-'
	if(num < 0)
	{
		drawCharAt('-', x, y, fore_color, back_color, char_scale, video_base, table);
		i++;
		num = 0 - num;
	}
	
	//descobrir a ordem de grandeza do numero
	int ordem = 1;
	while(num / ordem >= 10) ordem *= 10;
	
	//da esquerda para a direita, imprimir os algarismos
	while(true)
	{
		int digito = num / ordem;
		drawCharAt(digito + '0', x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		num -= digito * ordem;
		if(ordem == 1)
			break;
		ordem /= 10;
		i++;
	}
}



void drawTitle(char * title, int xi, int yi, int xf, int yf, int fore_color, int back_color, char * base, int char_scale, char * table)
{
	// Rectângulo de fora
	draw_line(xi, yi, xf, yi, fore_color, base);	// linha horizontal superior
	draw_line(xi, yi, xi, yf, fore_color, base);	// linha vertical esquerda
	draw_line(xi, yf, xf, yf, fore_color, base);	// linha horizontal inferior
	draw_line(xf, yi, xf, yf, fore_color, base);	// linha vertical direita

	// Rectângulo de dentro
	draw_line(xi + 150, yi + 70, xf - 150, yi + 70, fore_color, base);	// linha horizontal superior
	draw_line(xi + 150, yi + 70, xi + 150, yf - 70, fore_color, base);	// linha vertical esquerda
	draw_line(xi + 150, yf - 70, xf - 150, yf - 70, fore_color, base);	// linha horizontal inferior
	draw_line(xf - 150, yi + 70, xf - 150, yf - 70, fore_color, base);	// linha vertical direita

	// Título
	drawStringAt(title, xi + 10, yi + 10, fore_color, back_color, char_scale, base, table);
}



void draw_circle(int x0, int y0, int radius , int color, char *base)
{
  int f = 1 - radius;
  int ddF_x = 1;
  int ddF_y = -2 * radius;
  int x = 0;
  int y = radius;

	set_pixel(x0, y0 + radius , color , base );
  	set_pixel(x0, y0 - radius , color , base );
  	set_pixel(x0 + radius, y0 , color , base );
  	set_pixel(x0 - radius, y0 , color , base );

  while(x < y)
  {
    // ddF_x == 2 * x + 1;
    // ddF_y == -2 * y;
    // f == x*x + y*y - radius*radius + 2*x - y + 1;
    if(f >= 0)
    {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    set_pixel(x0 + x, y0 + y , color , base );
    set_pixel(x0 - x, y0 + y , color , base );
    set_pixel(x0 + x, y0 - y , color , base );
    set_pixel(x0 - x, y0 - y , color , base );
    set_pixel(x0 + y, y0 + x , color , base );
    set_pixel(x0 - y, y0 + x , color , base );
    set_pixel(x0 + y, y0 - x , color , base );
    set_pixel(x0 - y, y0 - x , color , base );
  }
}


void drawBox( int xi, int yi, int xf, int yf, int fore_color, int fill , char * base )
{
	// Rectângulo de fora
	draw_line(xi, yi, xf, yi, fore_color, base);	// linha horizontal superior
	draw_line(xi, yi, xi, yf, fore_color, base);	// linha vertical esquerda
	draw_line(xi, yf, xf, yf, fore_color, base);	// linha horizontal inferior
	draw_line(xf, yi, xf, yf, fore_color, base);	// linha vertical direita
	if ( fill ) //Preenchimento
	{
		if ( yf < yi )
		{
			int tmp = yi;
			yi = yf;
			yf = tmp;
		}
		while ( yi < yf )
		{
				draw_line(xi, yi + 1, xf, yi + 1, fore_color, base);
				++yi;
		}
	}
	

}

static char * table = NULL;

void drawSpriteTitle( int x , int y , char * base )
{
	if ( table == NULL )
	{
		table = ( char * )malloc(256 * CHR_H * sizeof(char) );
		load_char_table(table);
	}
	drawTitle("HANGMAN", 310, 50, 440, 100, FORECOLOR, BACKCOLOR, base, 2, table);
}
